#include "QSPrecompiledHeaders.h"
#include "QSGameSystemImpl.h"
#include "QSCommand.h"

using namespace QS;

void GameSystemImpl::initialize()
{
	addCommand(Command("bind", &GameSystemImpl::cmdBind, this));
	addCommand(Command("print", &GameSystemImpl::cmdPrint, this));
	addCommand(Command("quit", &GameSystemImpl::cmdQuit, this));

	mEngine->getEventSystem()->addEventListener(this);
}

void GameSystemImpl::addCommand(const Command& cmd)
{
	if (findCommand(cmd.getName()))
	{
		print(cmd.getName() + " already registered.");
		return;
	}
	mCommands.push_back(cmd);
}

void GameSystemImpl::shutdown()
{
	clearCommands();
	mEngine->getEventSystem()->removeEventListener(this);
}

void GameSystemImpl::clearCommands()
{
	mCommands.clear();
}

void GameSystemImpl::processEvent(const Event& e)
{
	if (e.getTypeId() == EventType::KeyDown)
	{
		const KeyEventArgs* args = static_cast<const KeyEventArgs*>(e.getArgs());
		if (mBindings.find(args->key) != mBindings.end())
			executeCommand(mBindings[args->key]);
	}
}

void GameSystemImpl::bind(Key::Enum key, const String& command)
{
	mBindings[key] = command;
}

void GameSystemImpl::executeCommand(const String& text)
{
	String command, temp;
	CommandArgs args;

	//parse the command string to find the command name and args
	for (const char* c=text.c_str() ; c ; c++)
	{
		if (*c == ' ' || *c == '\t' || *c == 0)
		{
			if (temp.size() > 0)
			{
				if (command.size() == 0)
					command = temp;
				else 
					args.push_back(temp);
			
				temp.clear();
			}
			if (*c)				
				continue;
			else
				break;
		}
		else
		{
			temp.push_back(*c);
		}
	}

	Command* target = findCommand(command);
	if (target)
		target->call(args);
	else if (command.size() > 0)
		print("Unknown command \"" + command + "\"");
}

Command* GameSystemImpl::findCommand(const String& name)
{
	for (size_t i=0 ; i<mCommands.size() ; i++)
	{
		if (mCommands[i].getName() == name)
		{
			return &mCommands[i];
		}
	}

	return 0;
}

void GameSystemImpl::cmdQuit(const CommandArgs&)
{
	mEngine->getEventSystem()->postEvent(Event(EventType::Quit));
}

void GameSystemImpl::cmdPrint(const CommandArgs& args)
{
	String text;
	for (size_t i=0 ; i<args.size() ; i++)
		text += args[i] + " ";

	print(text);
}

void GameSystemImpl::cmdBind(const CommandArgs& args)
{
	size_t argc = args.size();
	if (argc != 1 && argc != 2)
	{
		print("bind <key> [command] : attach a command to a key\n");
		return;
	}
	
	Key::Enum k = Key::fromString(args[0]);
	if (k == -1)
	{
		print("\"" + args[0] + "\" isn't a valid key");
		return;
	}

	if (argc == 1)
	{
		if (mBindings.find(k) != mBindings.end())
			print("\"" + args[0] + "\" = \"" + mBindings[k] + "\"");
		else
			print("\"" + args[0] + "\" is not bound");
		return;
	}

	String cmd;
	for(size_t i=1 ; i<argc ; i++)
	{
		cmd += args[i];
		if (i != argc-1)
			cmd += " ";
	}
	mBindings[k] = cmd;
}

void GameSystemImpl::print(const String& text)
{
	GuiSystem* gui = mEngine->getGuiSystem();
	gui->printToConsole(text);
}